﻿using SherpaOnnx;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace SpeechRecognitionCSharp
{
    /// <summary>
    /// 处理语音识别结果，为文本添加标点符号和时间戳
    /// </summary>
    internal class ParseResult
    {
        private string _result;
        private string _resultWithTimespanLrc;
        private string _resultWithTimespanSrt;
        private OfflineRecognizerResult _rawResult;
        private string[] sentence;
        private TimeRegionStruct[] timeRegionStructs;

        /// <summary>
        /// 构造函数，接收识别结果并处理
        /// </summary>
        /// <param name="result">语音识别原始结果</param>
        public ParseResult(OfflineRecognizerResult result) 
        {
            _rawResult = result;
            ProcessResult();
        }

        /// <summary>
        /// 处理识别结果，直接对标点符号进行分割，计算句子起始时间并生成带时间戳的结果
        /// </summary>
        private void ProcessResult()
        {
            if (_rawResult == null || string.IsNullOrEmpty(_rawResult.Text))
            {
                _result = string.Empty;
                _resultWithTimespanLrc = string.Empty;
                _resultWithTimespanSrt = string.Empty;
                sentence = new string[0];
                timeRegionStructs = new TimeRegionStruct[0];
                return;
            }

            // 使用原始文本
            _result = _rawResult.Text;
            
            // 直接对标点符号进行分割，放到sentence数组
            SplitTextByPunctuation();
            
            // 计算每个sentence的起始时间，放到timeRegionStructs数组
            CalculateSentenceStartTimes();
            
            // 生成带时间戳的结果：[时间戳] 句子内容
            GenerateFormattedResultWithTimespan();
            
            // 生成SRT格式的结果
            GenerateResultWithTimespanSrt();
        }

        /// <summary>
        /// 直接对标点符号进行分割，获取句子数组
        /// </summary>
        private void SplitTextByPunctuation()
        {
            if (string.IsNullOrEmpty(_result))
            {
                sentence = new string[0];
                return;
            }

            // 使用正则表达式分割句子
            // 分割符为句号、问号、感叹号、逗号
            string[] sentences = Regex.Split(_result, @"([。.,，!！?？])");
            
            // 合并句子和标点符号
            List<string> mergedSentences = new List<string>();
            for (int i = 0; i < sentences.Length - 1; i += 2)
            {
                if (!string.IsNullOrEmpty(sentences[i]))
                {
                    mergedSentences.Add(sentences[i] + sentences[i + 1]);
                }
            }
            
            // 确保mergedSentences中每条句子长度都小于30个字符
            List<string> processedSentences = new List<string>();
            foreach (var sentence in mergedSentences)
            {
                if (sentence.Length > 30)
                {
                    // 简单拆分：从中间位置分开
                    int splitPoint = sentence.Length / 2;
                    
                    // 尝试在合适的位置拆分（如空格或标点符号附近）
                    for (int j = splitPoint; j > Math.Max(0, splitPoint - 10); j--)
                    {
                        if (char.IsWhiteSpace(sentence[j]) || ",，.。!?！？;".Contains(sentence[j]))
                        {
                            splitPoint = j + 1;
                            break;
                        }
                    }
                    
                    // 拆分句子
                    string part1 = sentence.Substring(0, splitPoint);
                    string part2 = sentence.Substring(splitPoint);
                    
                    processedSentences.Add(part1);
                    processedSentences.Add(part2);
                }
                else
                {
                    processedSentences.Add(sentence);
                }
            }
            
            // 使用处理后的句子列表
            mergedSentences = processedSentences;
            
            // 处理短句子合并：小于4个汉字或2个单词的句子可能与前一个句子合并
            // 但确保合并后每个句子长度不超过30个字符
            List<string> finalSentences = new List<string>();
            for (int i = 0; i < mergedSentences.Count; i++)
            {
                string currentSentence = mergedSentences[i];
                
                // 检查是否是短句子
                bool isShortSentence = IsShortSentence(currentSentence);
                
                // 如果是短句子且不是第一个句子，并且合并后前一个句子长度不会超过30个字符，则合并
                if (isShortSentence && finalSentences.Count > 0 && 
                    (finalSentences[finalSentences.Count - 1].Length + currentSentence.Length) <= 30)
                {
                    finalSentences[finalSentences.Count - 1] += currentSentence;
                }
                else
                {
                    finalSentences.Add(currentSentence);
                }
            }
            
            // 如果最后一个元素不是标点符号，也添加到结果中
            if (sentences.Length > 0 && sentences[sentences.Length - 1].Length > 0 && !IsEndPunctuation(sentences[sentences.Length - 1][0]))
            {
                string lastSentence = sentences[sentences.Length - 1];
                
                // 检查最后一个句子是否为短句子
                bool isLastSentenceShort = IsShortSentence(lastSentence);
                
                // 如果是短句子且不是第一个句子，并且合并后前一个句子长度不会超过30个字符，则合并
                if (isLastSentenceShort && finalSentences.Count > 0 && 
                    (finalSentences[finalSentences.Count - 1].Length + lastSentence.Length) <= 30)
                {
                    finalSentences[finalSentences.Count - 1] += lastSentence;
                }
                else
                {
                    finalSentences.Add(lastSentence);
                }
            }
            
            sentence = finalSentences.ToArray();
        }
        
        /// <summary>
        /// 检查句子是否为短句子（小于4个汉字或2个单词）
        /// </summary>
        /// <param name="sentence">要检查的句子</param>
        /// <returns>是否为短句子</returns>
        private bool IsShortSentence(string sentence)
        {
            if (string.IsNullOrEmpty(sentence))
                return true;
            
            // 去除标点符号
            string textWithoutPunctuation = Regex.Replace(sentence, "[。.,，!！?？;:：；]", "");
            
            // 计算中文字符数量
            int chineseCharCount = 0;
            foreach (char c in textWithoutPunctuation)
            {
                if (c >= 0x4e00 && c <= 0x9fff) // 中文字符范围
                {
                    chineseCharCount++;
                }
            }
            
            // 计算单词数量（以空格分隔）
            int wordCount = textWithoutPunctuation.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
            
            // 小于4个汉字或2个单词的视为短句子
            return chineseCharCount < 4 || wordCount < 2;
        }
        
        /// <summary>
        /// 计算每个句子的起始时间
        /// </summary>
        private void CalculateSentenceStartTimes()
        {
            if (sentence == null || sentence.Length == 0)
            {
                timeRegionStructs = new TimeRegionStruct[0];
                return;
            }

            // 初始化时间区域数组
            timeRegionStructs = new TimeRegionStruct[sentence.Length];
            
            // 如果没有时间戳信息，使用均匀分布
            if (_rawResult.Timestamps == null || _rawResult.Timestamps.Length == 0)
            {
                for (int i = 0; i < sentence.Length; i++)
                {
                    timeRegionStructs[i].timeStart = FormatTime(i * 5.0); // 简单假设每句5秒
                    timeRegionStructs[i].timeEnd = FormatTime((i + 1) * 5.0);
                }
                return;
            }
            
            // 计算每个句子的时间戳
            // 这里使用简单的字符比例分配方式，实际应用中可能需要更复杂的算法
            double totalDuration = _rawResult.Timestamps[_rawResult.Timestamps.Length - 1];
            double charDuration = totalDuration / _result.Length;
            
            int currentPos = 0;
            for (int i = 0; i < sentence.Length; i++)
            {
                double startTime = currentPos * charDuration;
                double endTime = Math.Min((currentPos + sentence[i].Length) * charDuration, totalDuration);
                
                timeRegionStructs[i].timeStart = FormatTime(startTime);
                timeRegionStructs[i].timeEnd = FormatTime(endTime);
                
                currentPos += sentence[i].Length;
            }
        }
        
        /// <summary>
        /// 生成带时间戳的结果
        /// </summary>
        private void GenerateFormattedResultWithTimespan()
        {
            if (sentence == null || sentence.Length == 0 || timeRegionStructs == null || timeRegionStructs.Length == 0)
            {
                _resultWithTimespanLrc = _result;
                _resultWithTimespanSrt = _result;
                return;
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < sentence.Length && i < timeRegionStructs.Length; i++)
            {
                sb.AppendFormat("[{0}] {1}", timeRegionStructs[i].timeStart.Substring(3), sentence[i]);
                if (i < sentence.Length - 1)
                {
                    sb.AppendLine();
                }
            }
            
            _resultWithTimespanLrc = sb.ToString();
        }
        
        /// <summary>
        /// 生成SRT格式的结果
        /// </summary>
        private void GenerateResultWithTimespanSrt()
        {
            if (sentence == null || sentence.Length == 0 || timeRegionStructs == null || timeRegionStructs.Length == 0)
            {
                _resultWithTimespanSrt = _result;
                return;
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < sentence.Length && i < timeRegionStructs.Length; i++)
            {
                // SRT格式：序号
                sb.AppendLine((i + 1).ToString());
                
                // SRT格式：时间码（开始时间 --> 结束时间）
                string startTime = ConvertToSrtTimeFormat(timeRegionStructs[i].timeStart);
                string endTime = ConvertToSrtTimeFormat(timeRegionStructs[i].timeEnd);
                sb.AppendLine($"{startTime} --> {endTime}");
                
                // SRT格式：字幕文本
                sb.AppendLine(sentence[i]);
                
                // SRT格式：空行分隔
                if (i < sentence.Length - 1)
                {
                    sb.AppendLine();
                }
            }
            
            _resultWithTimespanSrt = sb.ToString();
        }
        
        /// <summary>
        /// 将LRC时间格式转换为SRT时间格式
        /// LRC格式: 00:52.10
        /// SRT格式: 00:00:52,100
        /// </summary>
        /// <param name="lrcTimeFormat">LRC格式的时间字符串</param>
        /// <returns>SRT格式的时间字符串</returns>
        private string ConvertToSrtTimeFormat(string lrcTimeFormat)
        {
            try
            {
                // 解析LRC时间格式
                string[] parts = lrcTimeFormat.Split(':');
                if (parts.Length < 2)
                {
                    return "00:00:00,000";
                }
                
                int minutes = int.Parse(parts[1]);
                string[] secondsParts = parts[2].Split('.');
                int seconds = int.Parse(secondsParts[0]);
                int milliseconds = secondsParts.Length > 1 ? int.Parse(secondsParts[1])  : 0; // LRC格式的毫秒通常是两位，SRT需要三位
                
                // 计算总秒数，处理超过60分钟的情况
                int totalSeconds = minutes * 60 + seconds;
                int hours = totalSeconds / 3600;
                minutes = (totalSeconds % 3600) / 60;
                seconds = totalSeconds % 60;
                
                // 格式化为SRT时间格式：00:00:52,100
                return string.Format("{0:D2}:{1:D2}:{2:D2},{3:D3}", hours, minutes, seconds, milliseconds);
            }
            catch
            {
                return "00:00:00,000";
            }
        }

        /// <summary>
        /// 为中文文本添加标点符号
        /// </summary>
        /// <param name="text">需要添加标点的文本</param>
        /// <returns>添加标点后的文本</returns>
        private string AddPunctuationToChineseText(string text)
        {
            if (string.IsNullOrEmpty(text))
                return string.Empty;

            // 去除多余空格
            text = Regex.Replace(text, @"\s+", "");
            
            // 简单的标点符号添加逻辑
            // 在实际应用中，可能需要使用更复杂的NLP模型来确定合适的标点位置
            StringBuilder sb = new StringBuilder(text);
            
            // 句子结束的模式：句号、问号、感叹号前添加句号
            // 这里使用简单的规则，在逗号应该出现的位置添加逗号
            // 注意：这只是一个基础实现，实际应用中需要更复杂的逻辑或NLP模型
            
            // 在句子中间适当位置添加逗号
            // 这里使用简单的长度规则，每15-20个字符添加一个逗号
            for (int i = 15; i < sb.Length; i += 15)
            {
                if (i < sb.Length && !IsPunctuation(sb[i]))
                {
                    sb.Insert(i, '，'); // 插入中文逗号
                    i++; // 跳过插入的逗号
                }
            }
            
            // 确保句子以句号结尾
            if (sb.Length > 0 && !IsEndPunctuation(sb[sb.Length - 1]))
            {
                sb.Append('。'); // 插入中文句号
            }
            
            return sb.ToString();
        }

        /// <summary>
        /// 将文本分割成句子
        /// </summary>
        private void SplitIntoSentences()
        {
            if (string.IsNullOrEmpty(_result))
            {
                sentence = new string[0];
                return;
            }

            // 使用正则表达式分割句子
            // 分割符为句号、问号、感叹号
            string[] sentences = Regex.Split(_result, @"([。.!！?？])");
            
            // 合并句子和标点符号
            List<string> mergedSentences = new List<string>();
            for (int i = 0; i < sentences.Length - 1; i += 2)
            {
                if (!string.IsNullOrEmpty(sentences[i]))
                {
                    mergedSentences.Add(sentences[i] + sentences[i + 1]);
                }
            }
            
            // 如果最后一个元素不是标点符号，也添加到结果中
            if (sentences.Length > 0 && sentences[sentences.Length - 1].Length > 0 && !IsEndPunctuation(sentences[sentences.Length - 1][0]))
            {
                mergedSentences.Add(sentences[sentences.Length - 1]);
            }
            
            sentence = mergedSentences.ToArray();
        }

        /// <summary>
        /// 计算每个句子的起止时间
        /// </summary>
        private void CalculateSentenceTimeRegions()
        {
            if (sentence == null || sentence.Length == 0)
            {
                timeRegionStructs = new TimeRegionStruct[0];
                return;
            }

            // 初始化时间区域数组
            timeRegionStructs = new TimeRegionStruct[sentence.Length];
            
            // 如果没有时间戳信息，使用均匀分布
            if (_rawResult.Timestamps == null || _rawResult.Timestamps.Length == 0)
            {
                for (int i = 0; i < sentence.Length; i++)
                {
                    timeRegionStructs[i].timeStart = FormatTime(i * 5.0); // 简单假设每句5秒
                    timeRegionStructs[i].timeEnd = FormatTime((i + 1) * 5.0);
                }
                return;
            }
            
            // 计算每个句子的时间戳
            // 这里使用简单的字符比例分配方式，实际应用中可能需要更复杂的算法
            double totalDuration = _rawResult.Timestamps[_rawResult.Timestamps.Length - 1];
            double charDuration = totalDuration / _result.Length;
            
            int currentPos = 0;
            for (int i = 0; i < sentence.Length; i++)
            {
                double startTime = currentPos * charDuration;
                double endTime = Math.Min((currentPos + sentence[i].Length) * charDuration, totalDuration);
                
                timeRegionStructs[i].timeStart = FormatTime(startTime);
                timeRegionStructs[i].timeEnd = FormatTime(endTime);
                
                currentPos += sentence[i].Length;
            }
        }

        /// <summary>
        /// 格式化时间为hh:mm:ss.ff格式
        /// </summary>
        /// <param name="seconds">秒数</param>
        /// <returns>格式化后的时间字符串</returns>
        private string FormatTime(double seconds)
        {
            int hours = (int)(seconds / 3600);
            int minutes = (int)((seconds % 3600) / 60);
            int secs = (int)(seconds % 60);
            int millisecs = (int)((seconds - (int)seconds) * 100);
            
            // 格式为hh:mm:ss.ff，例如00:52.10
            return string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", hours, minutes, secs, millisecs);
        }

        /// <summary>
        /// 生成带时间戳的结果文本
        /// </summary>
        private void GenerateResultWithTimespan()
        {
            if (sentence == null || sentence.Length == 0 || timeRegionStructs == null || timeRegionStructs.Length == 0)
            {
                _resultWithTimespanLrc = _result;
                _resultWithTimespanSrt = _result;
                return;
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < sentence.Length && i < timeRegionStructs.Length; i++)
            {
                sb.AppendFormat("[{0}]{1}", timeRegionStructs[i].timeStart, sentence[i]);
                if (i < sentence.Length - 1)
                {
                    sb.AppendLine();
                }
            }
            
            _resultWithTimespanLrc = sb.ToString();
            
            // 同时更新SRT格式的结果
            GenerateResultWithTimespanSrt();
        }

        /// <summary>
        /// 检查字符是否为标点符号
        /// </summary>
        /// <param name="c">要检查的字符</param>
        /// <returns>是否为标点符号</returns>
        private bool IsPunctuation(char c)
        {
            return ",，。.!！?？;；:：" .Contains(c);
        }

        /// <summary>
        /// 检查字符是否为句子结束标点符号
        /// </summary>
        /// <param name="c">要检查的字符</param>
        /// <returns>是否为句子结束标点符号</returns>
        private bool IsEndPunctuation(char c)
        {
            return ".。!！?？" .Contains(c);
        }

        /// <summary>
        /// 获取添加标点后的结果文本
        /// </summary>
        public string Result
        {
            get { return _result; }
        }

        /// <summary>
        /// 获取带时间戳的结果文本(LRC格式)
        /// </summary>
        public string ResultWithTimespanLrc
        {
            get { return _resultWithTimespanLrc; }
        }
        
        /// <summary>
        /// 获取带时间戳的结果文本(SRT格式)
        /// </summary>
        public string ResultWithTimespanSrt
        {
            get { return _resultWithTimespanSrt; }
        }

        /// <summary>
        /// 获取原始识别结果
        /// </summary>
        public OfflineRecognizerResult RawResult
        {
            get { return _rawResult; }
        }

        /// <summary>
        /// 获取分割后的句子数组
        /// </summary>
        public string[] Sentences
        {
            get { return sentence; }
        }

        /// <summary>
        /// 获取句子对应的时间区域数组
        /// </summary>
        public TimeRegionStruct[] TimeRegionStructs
        {
            get { return timeRegionStructs; }
        }


        public void ExportResult(String filePath, fileExportType type) {

            string exportFilePath = string.Empty; 
            switch (type)
            {
                case fileExportType.NONE:
                    break;
                case fileExportType.TXT:
                    exportFilePath = Path.ChangeExtension(filePath, ".txt");
                    File.WriteAllText(exportFilePath, this.Result);
                    break;
                case fileExportType.LRC:
                    exportFilePath = Path.ChangeExtension(filePath, ".lrc");
                    File.WriteAllText(exportFilePath, this.ResultWithTimespanLrc);
                    break;
                case fileExportType.SRT:
                    exportFilePath = Path.ChangeExtension(filePath, ".srt");
                    File.WriteAllText(exportFilePath, this.ResultWithTimespanSrt);
                    break;
                default:
                    break;
            }
        }


    }

    /// <summary>
    /// 表示句子的时间区域结构
    /// </summary>
    struct TimeRegionStruct 
    {
        /// <summary>
        /// 句子开始时间
        /// </summary>
        public string timeStart;
        /// <summary>
        /// 句子结束时间
        /// </summary>
        public string timeEnd;
    }

    public enum fileExportType { 
        NONE,
        TXT,
        LRC,
        SRT
    
    
    }

}
